﻿using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace AzureContrib.WindowsAzure.Security
{
	/// <summary>
	/// Helper class for encrypting and decrypting in Azure using public/private key
	/// </summary>
	public static class X509CertificateHelper
	{
		/// <summary>
		/// Load a certificate 
		/// </summary>
		/// <param name="storeName"></param>
		/// <param name="storeLocation"></param>
		/// <param name="thumbprint"></param>
		/// <returns></returns>
		public static X509Certificate2 LoadCertificate(StoreName storeName, StoreLocation storeLocation, string thumbprint)
		{
			// The following code gets the cert from the keystore
			X509Store store = new X509Store(storeName, storeLocation);

			store.Open(OpenFlags.ReadOnly);

			X509Certificate2Collection certCollection = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);

			X509Certificate2Enumerator enumerator = certCollection.GetEnumerator();

			X509Certificate2 cert = null;

			while (enumerator.MoveNext())
			{
				cert = enumerator.Current;
			}

			return cert;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="plainData"></param>
		/// <param name="fOAEP"></param>
		/// <param name="certificate"></param>
		/// <returns></returns>
		public static byte[] Encrypt(byte[] plainData, bool fOAEP, X509Certificate2 certificate)
		{
			if (plainData == null)
			{
				throw new ArgumentNullException("plainData");
			}

			if (certificate == null)
			{
				throw new ArgumentNullException("certificate");
			}

			using (RSACryptoServiceProvider provider = new RSACryptoServiceProvider())
			{
				provider.FromXmlString(GetPublicKey(certificate));

				// We use the public key to encrypt.
				return provider.Encrypt(plainData, fOAEP);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="encryptedData"></param>
		/// <param name="fOAEP"></param>
		/// <param name="certificate"></param>
		/// <returns></returns>
		public static byte[] Decrypt(byte[] encryptedData, bool fOAEP, X509Certificate2 certificate)
		{
			if (encryptedData == null)
			{
				throw new ArgumentNullException("encryptedData");
			}

			if (certificate == null)
			{
				throw new ArgumentNullException("certificate");
			}

			using (RSACryptoServiceProvider provider = (RSACryptoServiceProvider)certificate.PrivateKey)
			{
				// We use the private key to decrypt.
				return provider.Decrypt(encryptedData, fOAEP);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="certificate"></param>
		/// <returns></returns>
		public static string GetPublicKey(X509Certificate2 certificate)
		{
			if (certificate == null)
			{
				throw new ArgumentNullException("certificate");
			}

			return certificate.PublicKey.Key.ToXmlString(false);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="certificate"></param>
		/// <returns></returns>
		public static string GetXmlKeyPair(X509Certificate2 certificate)
		{
			if (certificate == null)
			{
				throw new ArgumentNullException("certificate");
			}

			if (!certificate.HasPrivateKey)
			{
				throw new ArgumentException("certificate does not have a PK");
			}

			return certificate.PrivateKey.ToXmlString(true);
		}
	}
}